#include "Explosion.h"
#include "../PhysicsLogic.h"
#include "../Sound.h"
#include "../Game.h"
#include "../Renderer.h"

LinkedList<Explosion*> Explosion::all;
LinkedList<Explosion*> Explosion::toDelete;

SurfaceRenderingData Explosion::srd;

const float Explosion::maxRadius = 3.0f;
const float Explosion::stepRadius = 15.0f;
const float Explosion::force = 250.0f;

void Explosion::Load() { //static
	srd.SetColor(1.0f, 0.5f, 0.0f, 0.5f);
}

Explosion::Explosion(const NxVec3& pos) {
	Game::log.LogDebug(StringBuilder() << "Explosion " << this);

	NxForceFieldLinearKernelDesc linearKernelDesc;
	linearKernelDesc.constant = NxVec3(force,0,0);

	linearKernel = PhysicsLogic::GetScene()->createForceFieldLinearKernel(linearKernelDesc);

	NxForceFieldDesc fieldDesc;
	fieldDesc.kernel = linearKernel;
	fieldDesc.coordinates = NX_FFC_SPHERICAL;
	fieldDesc.pose.t = pos;
 
	forceField = PhysicsLogic::GetScene()->createForceField(fieldDesc);

	NxSphereForceFieldShapeDesc sphereDesc;
	sphereDesc.radius = 0.1;

	sphereForceFieldShape = forceField->getIncludeShapeGroup().createShape(sphereDesc);

	all.Add(this);

	Sound::Play(Sound::SAMPLE_EXPLOSION, 0.4f, (pos-PhysicsLogic::GetCamera().GetPosition())*0.15f, PhysicsLogic::GetCameraForward());
}

Explosion::~Explosion() {
	PhysicsLogic::GetScene()->releaseForceField(*forceField);
	PhysicsLogic::GetScene()->releaseForceFieldLinearKernel(*linearKernel);

	Game::log.LogDebug(StringBuilder() << "~Explosion " << this);
}

float Explosion::GetRadius() {
	return sphereForceFieldShape->isSphere()->getRadius();
}

void Explosion::Tick(float elapsedTime) {
	const float newRadius = GetRadius() + stepRadius * elapsedTime;
	sphereForceFieldShape->isSphere()->setRadius(newRadius);

	const NxSphere worldSphere(forceField->getPose().t, GetRadius());
	const NxU32 nbShapes = 32;
	NxShape** shapes = new NxShape*[nbShapes];
	for (NxU32 i=0; i<nbShapes; ++i) {
		shapes[i] = NULL;
	}
	PhysicsLogic::GetScene()->overlapSphereShapes(worldSphere, NX_DYNAMIC_SHAPES, nbShapes, shapes, NULL);
	for (NxU32 i=0; i<nbShapes; ++i) {
		NxShape* pickedShape = shapes[i];
		if(pickedShape) {
			NxActor& pickedActor = pickedShape->getActor();
			if(pickedActor.readBodyFlag(NX_BF_KINEMATIC)) {
				pickedActor.clearBodyFlag(NX_BF_KINEMATIC);
			}
		}
	}
	delete[] shapes;

	if(newRadius >= maxRadius) {
		toDelete.Add(this);
	}
}

void Explosion::Draw() {
	glDisable(GL_LIGHTING);
	glPushMatrix();
	float m[16];
	forceField->getPose().getColumnMajor44(m);
	glMultMatrixf(m);
	Renderer::SetMaterial(srd);
	Renderer::DrawSphere(GetRadius());
	glPopMatrix();
	glEnable(GL_LIGHTING);
}
